<?php
/**
 * Created by PhpStorm.
 * User: 1
 * Date: 2017-07-10
 * Time: 15:04
 */

namespace app\index\command;


use app\index\helper\CommandHelper;
use app\src\base\helper\ResultHelper;
use app\src\base\helper\ValidateHelper;
use app\src\sunsun\aph300\action\Aph300DeviceEventAction;
use app\src\sunsun\aph300\action\Aph300PhHisAction;
use app\src\sunsun\aph300\action\Aph300TcpLogAction;
use app\src\sunsun\aph300\action\Aph300TempHisAction;
use app\src\sunsun\aph300\logic\Aph300DeviceEventLogic;
use app\src\sunsun\aph300\logic\Aph300DeviceLogic;
use app\src\sunsun\aph300\model\Aph300DeviceEvent;
use app\src\sunsun\aq806\model\Aq806DeviceEvent;
use app\src\sunsun\common\action\PushLogAction;
use app\src\sunsun\common\logic\UserDeviceLogic;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class Aph300Command extends Command
{
    protected function initialize(Input $input, Output $output)
    {
        CommandHelper::loadLang(['zh-cn', 'en', 'zh-tw']);
    }

    protected function configure()
    {
        $this->setName('device:aph300')
            ->addOption('interval', '', Option::VALUE_OPTIONAL, 'device event process sleep {interval} seconds', 30)
            ->addOption('size', '', Option::VALUE_OPTIONAL, 'device event process sizes per time', 10)
            ->addOption('type', '', Option::VALUE_OPTIONAL, 'command type', 'clear')
            ->setDescription('aph300 device event process');
    }

    protected function execute(Input $input, Output $output)
    {
        $size = $input->getOption('size');
        $type = $input->getOption('type');
        $interval = $input->getOption('interval');
        $output->info('type= ' . $type);

        switch (strtolower($type)) {
            case 'process_event':
                $this->process_event($output, $size, $interval);
                break;
            case 'offline':
                $this->offline($output, $size);
                break;
            case 'clear':
                $this->clear($output);
                break;
            default:
                $this->clear($output);
                break;
        }
    }

    private function process_event(Output $output, $size = 30, $interval = 30)
    {
        while (true) {
            sleep($interval);
            $now = microtime(true);
            $output->info('process');
            $page = ['curpage' => 1, 'size' => $size];
            $userDeviceLogic = new UserDeviceLogic();
            $deviceEventLogic = new Aph300DeviceEventLogic();
            $result = $deviceEventLogic->query(['pro_status' => Aph300DeviceEvent::PRO_STATUS_NOT_PROCESS], $page, "id asc");
            $list = $result['info']['list'];
            $now = time();
            $allEntity = [];
            $phAction = new Aph300PhHisAction();
            foreach ($list as $item) {
                $id = $item['id'];
                $entity = ['id' => $id, 'update_time' => $now, 'pro_status' => Aph300DeviceEvent::PRO_STATUS_PROCESSED];
                $did = $item['did'];
                $eventType = $item['event_type'];
                $content = json_decode($item['event_info'], JSON_OBJECT_AS_ARRAY);
                if ($eventType == Aph300DeviceEvent::Event_Type_Data_PUSH) {
                    //记录ph值到数据库中
                    $ret = $phAction->add($did, $content, $item);
                    if (!ResultHelper::isSuccess($ret)) {
                        $entity['pro_status'] = Aph300DeviceEvent::PRO_STATUS_FAILED;
                    } else {
                        if (array_key_exists("ph", $content)) {
                            $ph = intval($content['ph']);
                            $output->info('ph= ' . $ph);
                            // 根据ph进行推送
                            $this->pushPhEventToUser($output, $did, $item, $ph);
                        }
                    }
                    //记录t值到数据库中
                    $ret = (new Aph300TempHisAction())->add($did, $content, $item);
                    if (!ResultHelper::isSuccess($ret)) {
                        $entity['pro_status'] = Aph300DeviceEvent::PRO_STATUS_FAILED;
                    } else {
                        if (array_key_exists("t", $content)) {
                            $temp = intval($content['t']);
                            $output->info('temp= ' . $temp);
                            // 根据temp进行推送
                            $this->pushTempEventToUser($output, $did, $item, $temp);
                        }
                    }
                    array_push($allEntity, $entity);
                    // 推送报警信息

                    continue;
                }

                $entity['pro_status'] = Aph300DeviceEvent::PRO_STATUS_FAILED;
                array_push($allEntity, $entity);
                continue;
            }
            if (count($allEntity) > 0) {
                $result = (new Aph300DeviceEventLogic())->saveAll($allEntity);
                if ($result['status']) {
                    $output->info(' save_all = ' . count($result['info']));
                }
            }

            $float = microtime(true) - $now;
            $output->info(' cost ' . $float . ' s');
        }
    }

    protected function pushPhEventToUser(Output $output, $did, $item, $ph)
    {

        $output->info('push ph event');
        $result = $this->getUsers($did);
        if (!ValidateHelper::isSuccess($result)) {
            return ResultHelper::error('没有绑定用户或报错');
        }

        $list = $result['info'];
        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new Aph300DeviceLogic());
        if (empty($ctrl_pwd)) {
            return ResultHelper::error('控制密码获取无效');
        }
        $time = $item['create_time'];
        $output->info('wait ph pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }
            $push_cfg = array_key_exists('push_cfg', $extra) ? $extra['push_cfg'] : 0;
            if (($push_cfg & 1) != 1) {
                // 只有二进制第一位为1的时候才进行ph报警
                continue;
            }

            $ph_l = array_key_exists('ph_l', $extra) ? $extra['ph_l'] : 0;
            $ph_h = array_key_exists('ph_h', $extra) ? $extra['ph_h'] : 0;
            if ($ph_l > 0 && $ph > 0 && $ph < $ph_l) {
                $eventType = 'ph_l';
                // PH过低报警
                $content = lang('equipment_ph_min', ['ph' => $ph / 100.0, 'ph_min' => $ph_l / 100.0], $lang);
            } elseif ($ph_h > 0 && $ph_h > 0 && $ph > $ph_h) {
                $eventType = 'ph_h';
                // PH过高报警
                $content = lang('equipment_ph_max', ['ph' => $ph / 100.0, 'ph_max' => $ph_h / 100.0], $lang);
            } else {
                // 如果没有就无需推送
                continue;
            }
            // 如果10分钟前 已经推送过该信息
            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
            if ($isPushed) {
                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                continue;
            }
            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];
            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang('aph300', '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];

            if ($time > time() - 1800) {
                CommandHelper::pushUMeng($data);
            }
        }
        return ResultHelper::success('处理完成');
    }

    /**
     * 获取需要推送的用户id
     * @param $did
     * @return array
     */
    protected function getUsers($did)
    {
        $result = (new UserDeviceLogic())->query(['did' => $did], ['curpage' => 1, 'size' => 50]);

        if (!ValidateHelper::legalArrayResult($result) || empty($result['info']['list'])) {
            return ResultHelper::error('没有绑定用户,无需推送');
        }
        return ResultHelper::success($result['info']['list']);
    }

    protected function pushTempEventToUser(Output $output, $did, $item, $temp)
    {

        $output->info('push temp event');
        $result = $this->getUsers($did);
        if (!ValidateHelper::isSuccess($result)) {
            return ResultHelper::error('没有绑定用户或报错');
        }

        $list = $result['info'];
        $ctrl_pwd = CommandHelper::getCtrlPwd($did, new Aph300DeviceLogic());
        if (empty($ctrl_pwd)) {
            return ResultHelper::error('控制密码获取无效');
        }
        $time = $item['create_time'];
        $output->info('wait temp pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }
            $push_cfg = array_key_exists('push_cfg', $extra) ? $extra['push_cfg'] : 0;
            if (($push_cfg & 2) != 2) {
                // 只有二进制第二位为1的时候才进行temp报警
                continue;
            }

            $temp_l = array_key_exists('temp_l', $extra) ? $extra['temp_l'] : 0;
            $temp_h = array_key_exists('temp_h', $extra) ? $extra['temp_h'] : 10000;
            if ($temp_l > 0 && $temp > 0 && $temp < $temp_l) {
                $eventType = 'temp_l';
                // 过低报警
                $content = lang('aph300_temp_min', ['temp' => $temp / 10.0, 'temp_min' => $temp_l / 10.0], $lang);
            } elseif ($temp_h > 0 && $temp_h > 0 && $temp > $temp_h) {
                $eventType = 'temp_h';
                // 过高报警
                $content = lang('aph300_temp_max', ['temp' => $temp / 10.0, 'temp_max' => $temp_h / 10.0], $lang);
            } else {
                // 如果没有就无需推送
                continue;
            }
            // 如果10分钟前 已经推送过该信息
            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
            if ($isPushed) {
                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                continue;
            }
            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];
            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang('aph300', '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];
            if ($time > time() - 1800) {
                CommandHelper::pushUMeng($data);
            }
        }
        return ResultHelper::success('处理完成');
    }

    private function offline(Output $output, $size = 10)
    {
        $time = microtime(true);
        $output->info('offline start');
        $result = CommandHelper::offline_notify($size, new Aph300DeviceLogic(), 'aph300');
        $cost_time = microtime(true) - $time;
        if ($result['status']) {
            $cnt = count($result['info']);
            $output->info('effect ' . $cnt);
        }
        $output->info('cost ' . $cost_time . ' s');
        $output->info('offline end');
    }

    private function clear(Output $output)
    {
        $output->highlight('aph300 clear start');
        //1. tcp接口日志
        $now = time();
        $dataTimestamp = $now - 8 * 3600;
        (new Aph300TcpLogAction())->clearExpiredData($dataTimestamp);

        //2. 事件日志
        $dataTimestamp = $now - 10 * 3600;
        (new Aph300DeviceEventAction())->clearExpiredData($dataTimestamp);

        $dataTimestamp = $now - 60 * 24 * 3600;
        (new Aph300PhHisAction())->clearExpiredData($dataTimestamp);

        $dataTimestamp = $now - 60 * 24 * 3600;
        (new Aph300TempHisAction())->clearExpiredData($dataTimestamp);

        $output->highlight('aph300 clear end');
    }

    protected function pushEventToUser(Output $output, $list, $ctrl_pwd, $item)
    {
        $time = $item['create_time'];
        $did = $item['did'];
        $eventType = $item['event_type'];
        $output->info('wait pushing count = ' . count($list));
        foreach ($list as $deviceItem) {
            $uid = $deviceItem['uid'];
            $timezone = intval($deviceItem['timezone']);
            $lang = $deviceItem['lang'];
            $extra = json_decode($deviceItem['extra'], JSON_OBJECT_AS_ARRAY);
            if (!is_array($extra) || !array_key_exists("pwd", $extra) || ($extra['pwd'] != 'sunsun123456' && $extra['pwd'] != $ctrl_pwd)) {
                $output->info('did=' . $did . ' password illegal uid=' . $uid);
                // 密码不一致就不需要处理
                continue;
            }

            $localTime = gmdate('H:i:s', $timezone * 3600 + $time);
            $nickname = $deviceItem['device_nickname'];

            $content = lang('aph300_event_type_' . $eventType, [], $lang);
            // 如果10分钟前 已经推送过该信息
            $isPushed = (new PushLogAction())->log($uid, $did, $eventType);
            if ($isPushed) {
                $output->info('did=' . $did . ' last 10 min had pushed uid=' . $uid);
                continue;
            }

            $data = [
                'to_uid' => $uid,
                'title' => lang('device_notify_title', ['nickname' => $nickname, 'device_type' => lang('aph300', '', $lang)], $lang),
                'content' => lang('device_notify_content', ['nickname' => $nickname, 'time' => $localTime, 'content' => $content], $lang)
            ];

            if ($time > time() - 1800) {
                if (!CommandHelper::pushUMeng($data)) {
                    $entity['pro_status'] = Aq806DeviceEvent::PRO_STATUS_FAILED;
                }
            }
        }
    }
}